#include <iostream>
#include <string>

namespace MoveAndEnable_if
{
    /**
     * 移动语义与std::enable_if<>
     *      1、完美转发
     *      2、特殊成员函数模板
     *      3、使用std::enable_if<>禁用模板
     *      4、使用std::enable_if<>
     *      5、使用概念简化enable_if<>表达式
     */

    /**
     * 1、完美转发 std::forward<>
     *      完美转发通常与引用转发（也就是通用引用）一起结合使用
     */
    // 利用f函数将传入参数转发到对应类型g函数中
    // void g(int){
    //     std::cout << "int" <<std::endl;
    // }
    void g(int &)
    {
        std::cout << "int&" << std::endl;
    }

    void g(const int &)
    {
        std::cout << "const int&" << std::endl;
    }

    void g(int &&)
    {
        std::cout << "int&&" << std::endl;
    }

    template <typename T>
    void f(T &&val)
    {
        g(std::forward<T>(val));
    }

    /**
     * 2、特殊成员函数模板
     */
    class Person
    {
    public:
        // 使用通用引用进行转发: ！！！
        // 这里需要使用typename = std::enable_if_t<std::is_convertible_v<T, std::string>> 进行限制
        // 原因在于：当调用 Person p2(p1); 时，由于p1不是const类型，所以会优先匹配引用转发函数，而不是拷贝构造
        //          导致构造失败

        template <typename T>
        using EnableIfString = std::enable_if_t<std::is_convertible_v<T, std::string>>;

        template <typename T, typename = EnableIfString<T>>
        Person(T &&name) : m_name(name)
        {
            std::cout << "Person(T&&)" << std::endl;
        };

        Person(const Person &p) : m_name(p.m_name)
        {
            std::cout << "Person(const Person&)" << std::endl;
        };

        Person(Person &&p) : m_name(p.m_name)
        {
            std::cout << "Person(Person&&)" << std::endl;
        };

    private:
        std::string m_name;
    };

    /**
     * 3、使用 enable_if<> 禁用模板
     *      从 C++11 开始，标准库提供了辅助模板 std::enable_if<>，以在特定的编译时条件下忽略函数模板
     */
    template <typename T>
    typename std::enable_if<(sizeof(T) > 4), T>::type foo() // sizeof(T)>4 是一个表达式，传入模板需要加()
    {
        return T{};
    }

    // 4、使用 typename std::enable_if<true/false>::type / std::enable_if_t<true/false>

    /*
    /// Alias template for enable_if
    template<bool _Cond, typename _Tp = void>
        using enable_if_t = typename enable_if<_Cond, _Tp>::type;

    /// Define a member typedef @c type only if a boolean constant is true.
    template<bool, typename _Tp = void>
        struct enable_if
        { };

    // 若表达式结果为 true，其类型成员类型将产生一个类型:
    //      若没有传递第二个模板参数，则该类型为 void。
    //      否则，该类型就是第二个模板参数类型。
    // 若表达式结果为 false，则没有定义成员类型。由于名为 SFINAE 的模板特性 (替换失败不为过)，
    //      这将忽略使用 enable_if 表达式的函数模板。
    // Partial specialization for true.
    template<typename _Tp>
        struct enable_if<true, _Tp>
        { typedef _Tp type; };
    */

    /*
    4.1.禁用特殊成员函数
        通常不能使用 enable_if<> 来禁用预定义的复制/移动构造函数和/或赋值操作符。
            原因是成员函数模板永远不会算作特殊成员函数，并且在需要复制构造函数等情况下会忽略。
    */
    class C
    {
    public:
        C() = default;

        // C(C const volatile &) = delete;

        // 该函数在copy构造时被忽略，程序会默认调用默认copy构造
        // 如果想使用该函数进行copy构造，需要声明 C(C const volatile &) = delete; 原因还不清楚
        template <typename T>
        C(T const &)
        {
            // std::is_integral_v()
            std::cout << "tmpl copy constructor" << std::endl;
        }
        // MoveAndEnable_if::C x(1);
        // MoveAndEnable_if::C y{x}; // 调用 default copy constructor，而不会调用该函数

        // 使用enable_if<>禁用非int类型的构造函数模板的方法
        // template <typename T, std::enable_if_t<(!std::is_integral_v<T>)>> 
        // C(T const &)
        // {
        //     std::cout << "tmpl integer copy constructor" << std::endl;
        // }

        /**
         * 5、使用概念简化 enable_if<> 表达式(看编译器，依然不是cpp17标准的一部分)
         */
        

    };

};